package com.yanqu.road.server.gameplayer.module.player;

import com.yanqu.road.entity.config.expression.ExpressionInfo;
import com.yanqu.road.entity.enums.eBlacklistType;
import com.yanqu.road.entity.enums.eChatContentType;
import com.yanqu.road.entity.enums.eMessageType;
import com.yanqu.road.entity.message.BanChatUserData;
import com.yanqu.road.entity.player.UserChat;
import com.yanqu.road.entity.player.UserInfo;
import com.yanqu.road.entity.servercenter.ServerGroup;
import com.yanqu.road.logic.bussiness.player.ChatBussiness;
import com.yanqu.road.logic.config.ChannelConfig;
import com.yanqu.road.logic.config.GameConfig;
import com.yanqu.road.pb.cross.group.CrossGroupProto;
import com.yanqu.road.pb.union.cross.CrossUnionProto;
import com.yanqu.road.pb.worldmessage.WorldMessageProto;
import com.yanqu.road.server.GameServer;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.base.GeneralModule;
import com.yanqu.road.server.manger.ChatControlMgr;
import com.yanqu.road.server.manger.CrossUnionServerGroupMgr;
import com.yanqu.road.server.manger.ForbiddenWordMgr;
import com.yanqu.road.server.manger.ServerGroupMgr;
import com.yanqu.road.server.manger.player.BlacklistMgr;
import com.yanqu.road.server.manger.player.ChatConfigMgr;
import com.yanqu.road.server.manger.system.WhiteWordMgr;
import com.yanqu.road.server.manger.player.WorldMessageMgr;
import com.yanqu.road.server.manger.player.GamePlayerMgr;
import com.yanqu.road.server.pb.WorldMessagePb;
import com.yanqu.road.server.protocol.ClientProtocol;
import com.yanqu.road.utils.ConfigHelper;
import com.yanqu.road.utils.YanQuMessageUtils;
import com.yanqu.road.message.YanQuMessage;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.server.protocol.Protocol;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.property.PropertyHelper;
import com.yanqu.road.utils.string.StringUtils;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class ChatModule extends GeneralModule {
	/**
	 * 刷屏时间间隔，5秒内
	 */
	private final int BRUSH_SCREEN_TIME = 5000;
	/**
	 * 刷屏次数，5次内
	 */
	private final int BRUSH_SCREEN_TIMES = 5;
	/**
	 * 恢复聊天时间，超过10秒
	 */
	private final int RECOVER_CHAT_TIME = 10000;
	/**
	 * 上次各个频道发言时间
	 */
	private Map<Integer, Long> lastChatSendTimeMap = new ConcurrentHashMap<>();
	/**
	 * 各个频道刷屏次数，连续发送5条时间间隔小于5秒的消息判定为刷屏
	 */
	private Map<Integer, Integer> brushScreenTimesMap = new ConcurrentHashMap<>();
	/**
	 * 世界聊天屏蔽的敏感信息，只对自己显示
	 */
	private List<WorldMessageProto.WorldMessageTempMsg.Builder> forbiddenMessageMsgList = new ArrayList<>();
	/**
	 * 商会屏蔽词
	 */
	private List<WorldMessageProto.WorldMessageTempMsg.Builder> unionForbiddenMessageMsgList = new ArrayList<>();
	/**
	 * 跨服活动屏蔽词
	 */
	private Map<Integer, List<WorldMessageProto.WorldMessageTempMsg.Builder>> crossActivityForbiddenMessageMsgMap = new ConcurrentHashMap<>();
	/**
	 * 跨服分组屏蔽词
	 */
	private List<WorldMessageProto.WorldMessageTempMsg.Builder> crossGroupForbiddenMessageMsgList = new ArrayList<>();

	/**
	 * 跨服宴会屏蔽词
	 */
	private Map<String, List<WorldMessageProto.WorldMessageTempMsg.Builder>> crossBanquetForbiddenMessageMsgMap = new ConcurrentHashMap<>();
	/**
	 * 跨服联姻分组屏蔽词
	 */
	private List<WorldMessageProto.WorldMessageTempMsg.Builder> crossMarriageGroupForbiddenMessageMsgList = new ArrayList<>();

	/**
	 * 招商屏蔽词
	 */
	private List<WorldMessageProto.WorldMessageTempMsg.Builder> zhaoShangForbiddenMessageMsgList = new ArrayList<>();

	/**
	 * 系统分组聊天屏蔽词(美女走镖等)
	 */
	private Map<Integer, List<WorldMessageProto.WorldMessageTempMsg.Builder>> systemGroupForbiddenMessageMsgMap = new ConcurrentHashMap<>();

	private UserChat userChat;

	public ChatModule(GamePlayer player) {
		super(player);
	}

	@Override
	public boolean loadData()  {
		userChat = ChatBussiness.getUserChat(player.getUserId());
		return true;
	}

	@Override
	public boolean afterLoadData() {
		return false;
	}

	@Override
	public boolean saveData() {
		if(null != userChat){
			if(userChat.isInsertOption()){
				ChatBussiness.addUserChat(userChat);
			}else if(userChat.isUpdateOption()){
				ChatBussiness.updateUserChat(userChat);
			}
		}
		return true;
	}

	@Override
	public void loginSendMsg() {
		syncChatControlData();
		syncWorldMessage();
		syncCrossGroupChat();
	}

	private void syncWorldMessage(){

		//商会聊天
		if(!StringUtils.isNullOrEmpty(player.getUserInfo().getUnionUid())){
			CrossUnionProto.UnionMemberChatListCrossUploadMsg.Builder crossListReqMsg = CrossUnionProto.UnionMemberChatListCrossUploadMsg.newBuilder();
			for (WorldMessageProto.WorldMessageTempMsg.Builder builder : unionForbiddenMessageMsgList) {
				if(builder.getUserId() != player.getUserId()){
					continue;
				}
				crossListReqMsg.addMsgList(builder);
			}
			player.sendPacket(Protocol.C_UNION_MEMBER_CHAT_LIST, crossListReqMsg);
		}

		//世界聊天
		//开启商会分组时，上跨服
		long serverId = ConfigHelper.getLong("serverId");
		if(CrossUnionServerGroupMgr.getGroupServerCountByServerId(serverId) > 1){
			CrossUnionProto.UnionMemberChatListCrossUploadMsg.Builder crossListReqMsg = CrossUnionProto.UnionMemberChatListCrossUploadMsg.newBuilder();
			for (WorldMessageProto.WorldMessageTempMsg.Builder forbidden : forbiddenMessageMsgList) {
				if(forbidden.getUserId() != player.getUserId()){
					continue;
				}
				crossListReqMsg.addMsgList(forbidden);
			}
			//续上系统通知
			List<WorldMessageProto.WorldMessageTempMsg.Builder> systemMessageList = WorldMessageMgr.getSystemMessageMsgList();
			for (WorldMessageProto.WorldMessageTempMsg.Builder builder : systemMessageList) {
				crossListReqMsg.addMsgList(builder);
			}
			//拿黑名单
			crossListReqMsg.addAllBlackList(BlacklistMgr.getUserAllBlackList(player.getUserId(), eBlacklistType.Chat.getValue()));
			player.sendPacket(Protocol.C_CROSS_WORLD_CHAT_LIST, crossListReqMsg);
			return;
		}

		//世界聊天
		List<WorldMessageProto.WorldMessageTempMsg.Builder> tempWorldMessageList = WorldMessageMgr.getWorldMessageMsgList();
		List<WorldMessageProto.WorldMessageTempMsg.Builder> worldMessageList = new ArrayList<>();
		//增加黑名单过滤
		for (int i = tempWorldMessageList.size() - 1; i > 0; i--) {
			if(BlacklistMgr.isInLocalBlacklist(player.getUserId(), eBlacklistType.Chat.getValue(), tempWorldMessageList.get(i).getUserId())){
				continue;
			}
			worldMessageList.add(tempWorldMessageList.get(i));
			if(worldMessageList.size() >= WorldMessageMgr.MAX_MESSAGE_COUNT){
				break;
			}
		}
		worldMessageList.addAll(forbiddenMessageMsgList);
		worldMessageList.sort((o1, o2) -> (int) (o1.getSendTime() - o2.getSendTime()));
		while (worldMessageList.size() > WorldMessageMgr.MAX_MESSAGE_COUNT){
			worldMessageList.remove(0);
		}
		//系统通知
		List<WorldMessageProto.WorldMessageTempMsg.Builder> systemMessageList = WorldMessageMgr.getSystemMessageMsgList();
		//合并
		WorldMessageProto.WorldMessageListMsg.Builder messageList = WorldMessageProto.WorldMessageListMsg.newBuilder();
		for(WorldMessageProto.WorldMessageTempMsg.Builder message : worldMessageList){
			messageList.addDataList(message);
		}
		for(WorldMessageProto.WorldMessageTempMsg.Builder message : systemMessageList){
			messageList.addDataList(message);
		}

		player.sendPacket(Protocol.U_WORLD_MESSAGE_LIST, messageList);
	}

	private void syncCrossGroupChat(){
		ServerGroup serverGroup = ServerGroupMgr.getServerGroupByServerId(GameServer.getInstance().getServerId());
		if(null != serverGroup && serverGroup.isCrossChat()) {
			CrossGroupProto.CrossGroupChatListReqMsg.Builder reqMsg = CrossGroupProto.CrossGroupChatListReqMsg.newBuilder();
			reqMsg.setGroupId(serverGroup.getGroupId());
			YanQuMessage pbMsg = YanQuMessageUtils.buildMessage(Protocol.C_CROSS_GROUP_CHAT_LIST, reqMsg);
			GamePlayerMgr.sendPacket(player.getUserId(), pbMsg);
		}
	}

	public int chat(GamePlayer player, int type, int contentType, String content, int activityId,String banquetId, List<String> callUserNameList, String groupParam, boolean showIp){
		long lastSendTime = getLastChatSendTime(type);
		long nowTime = System.currentTimeMillis();
		int brushScreenTimes = getBrushScreenTimes(type);
		long offsetTime = nowTime - lastSendTime;
		//设置最近发言时间
		lastChatSendTimeMap.put(type, nowTime);
		if(brushScreenTimes > BRUSH_SCREEN_TIMES) {//超过刷屏次数
			if(offsetTime < RECOVER_CHAT_TIME){
				return GameErrorCode.E_MESSAGE_SEND_OFTEN;
			}
		}
		if(ChannelConfig.CHAT_LIMIT_SWITCH == 1) {//开启聊天限制
			if (eMessageType.WorldChat.getValue() == type) {//世界聊天
				int result = canWorldChat(content, nowTime);
				if (0 != result) {
					return result;
				}
			}
		}
		//检测表情合法性
		if (contentType == eChatContentType.Expression.getContentType()) {
			if (!StringUtils.isNumber(content)) {
				return GameErrorCode.E_MESSAGE_TYPE_CONTENT_NO_MATCH;
			}
			ExpressionInfo expressionInfo = ChatConfigMgr.getExpressionByNum(Integer.parseInt(content));
			//判断表情是否存在
			if (expressionInfo == null) {
				return GameErrorCode.E_MESSAGE_EXPRESSION_NO_FOUND;
			}
			//不是免费 判断表情是否解锁
			if (!expressionInfo.isFree() && !player.getModule(BagModule.class).hasEnoughGoods(expressionInfo.getItemId(), 1)) {
				return GameErrorCode.E_MESSAGE_EXPRESSION_LOCK;
			}
		}

		if(eMessageType.CrossGroupChat.getValue() == type){
			if(!player.getModule(CurrencyModule.class).currencyIsEnough(new Property(GameConfig.GAME_ITEM_CROSS_GROUP_CHAT, BigInteger.ONE))){
				return GameErrorCode.E_BAG_ITEM_NO_ENOUGH;
			}
		}

		if(eMessageType.ZhaoShangGroupChat.getValue() == type){
			if(!player.getModule(CurrencyModule.class).currencyIsEnough(new Property(GameConfig.ZHAO_SHANG_GROUP_CHAT_GAME_ITEM, BigInteger.ONE))){
				return GameErrorCode.E_BAG_ITEM_NO_ENOUGH;
			}
		}

		if(eMessageType.CrossGroupUnionRecruit.getValue() == type){
			Property cost = PropertyHelper.parseStringToProperty(GameConfig.GAME_ITEM_CROSS_GROUP_UNION_RECRUIT_CHAT);
			if(!player.getModule(CurrencyModule.class).currencyIsEnough(cost)){
				return GameErrorCode.E_BAG_ITEM_NO_ENOUGH;
			}
		}

		if(offsetTime < BRUSH_SCREEN_TIME){
			brushScreenTimes++;
			brushScreenTimesMap.put(type, brushScreenTimes);
		}else {
			brushScreenTimesMap.put(type, 0);
		}

		WorldMessageMgr.addTask(WorldMessageMgr.getChatTask(player, type, contentType, content, activityId, banquetId, nowTime, callUserNameList, groupParam, showIp));
		return 0;
	}

	private long getLastChatSendTime(int type){
		if(lastChatSendTimeMap.containsKey(type)){
			return lastChatSendTimeMap.get(type);
		}
		return 0;
	}

	private int getBrushScreenTimes(int type){
		if(brushScreenTimesMap.containsKey(type)){
			return brushScreenTimesMap.get(type);
		}
		return 0;
	}

	public void addForbiddenMessage(WorldMessageProto.WorldMessageTempMsg.Builder msg){
		if(msg.getType() == eMessageType.UnionChat.getValue()){
			if(unionForbiddenMessageMsgList.size() >= WorldMessageMgr.MAX_MESSAGE_COUNT){
				unionForbiddenMessageMsgList.remove(0);
			}
			unionForbiddenMessageMsgList.add(msg);
		}else if(msg.getType() == eMessageType.CrossActivityChat.getValue()) {
			if(!crossActivityForbiddenMessageMsgMap.containsKey(msg.getActivityId())){
				crossActivityForbiddenMessageMsgMap.put(msg.getActivityId(), new ArrayList<>());
			}
			List<WorldMessageProto.WorldMessageTempMsg.Builder> dataList = crossActivityForbiddenMessageMsgMap.get(msg.getActivityId());
			if (dataList.size() >= WorldMessageMgr.MAX_MESSAGE_COUNT) {
				dataList.remove(0);
			}
			dataList.add(msg);
		}else if(msg.getType() == eMessageType.CrossBanquetChat.getValue()) {
			if(!crossBanquetForbiddenMessageMsgMap.containsKey(msg.getBanquetId())){
				crossBanquetForbiddenMessageMsgMap.put(msg.getBanquetId(), new ArrayList<>());
			}
			List<WorldMessageProto.WorldMessageTempMsg.Builder> dataList = crossBanquetForbiddenMessageMsgMap.get(msg.getBanquetId());
			if (dataList.size() >= WorldMessageMgr.MAX_MESSAGE_COUNT) {
				dataList.remove(0);
			}
			dataList.add(msg);
		}else if(msg.getType() == eMessageType.CrossGroupChat.getValue() || msg.getType() == eMessageType.CrossGroupUnionRecruit.getValue()){
			if (crossGroupForbiddenMessageMsgList.size() >= WorldMessageMgr.MAX_MESSAGE_COUNT) {
				crossGroupForbiddenMessageMsgList.remove(0);
			}
			crossGroupForbiddenMessageMsgList.add(msg);
		}else if(msg.getType() == eMessageType.CrossMarriageGroupChat.getValue()){
			if (crossMarriageGroupForbiddenMessageMsgList.size() >= WorldMessageMgr.MAX_MESSAGE_COUNT) {
				crossMarriageGroupForbiddenMessageMsgList.remove(0);
			}
			crossMarriageGroupForbiddenMessageMsgList.add(msg);
		}else if(msg.getType() == eMessageType.ZhaoShangGroupChat.getValue()){
			if (zhaoShangForbiddenMessageMsgList.size() >= WorldMessageMgr.MAX_MESSAGE_COUNT) {
				zhaoShangForbiddenMessageMsgList.remove(0);
			}
			zhaoShangForbiddenMessageMsgList.add(msg);
		}else if(msg.getType() == eMessageType.SystemGroupChat.getValue()){
			List<WorldMessageProto.WorldMessageTempMsg.Builder> list = systemGroupForbiddenMessageMsgMap.get(msg.getActivityId());
			if(list == null){
				list = new ArrayList<>();
				systemGroupForbiddenMessageMsgMap.put(msg.getActivityId(), list);
			}
			if (list.size() >= WorldMessageMgr.MAX_MESSAGE_COUNT) {
				list.remove(0);
			}
			list.add(msg);
		} else {
			if (forbiddenMessageMsgList.size() >= WorldMessageMgr.MAX_MESSAGE_COUNT) {
				forbiddenMessageMsgList.remove(0);
			}
			forbiddenMessageMsgList.add(msg);
		}
	}

	public void clearUnionForbiddenMessage(){
		unionForbiddenMessageMsgList.clear();
	}

	public List<WorldMessageProto.WorldMessageTempMsg.Builder> getCrossActivityForbiddenMsg(int activityId){
		return crossActivityForbiddenMessageMsgMap.get(activityId);
	}

	public List<WorldMessageProto.WorldMessageTempMsg.Builder> getCrossBanquetForbiddenMsg(String banquetId){
		return crossBanquetForbiddenMessageMsgMap.get(banquetId);
	}

	public List<WorldMessageProto.WorldMessageTempMsg.Builder> getCrossGroupForbiddenMsg(){
		return new ArrayList<>(crossGroupForbiddenMessageMsgList);
	}

	public List<WorldMessageProto.WorldMessageTempMsg.Builder> getZhaoShangForbiddenMessageMsgList() {
		return new ArrayList<>(zhaoShangForbiddenMessageMsgList);
	}

	public  List<WorldMessageProto.WorldMessageTempMsg.Builder> getSystemGroupForbiddenMessageMsgMap(int systemId) {
		List list = systemGroupForbiddenMessageMsgMap.get(systemId);
		if(list != null){
			return new ArrayList<>(list);
		}
		return new ArrayList<>();
	}

	/**
	 * 是否屏蔽
	 */
	public boolean isForbiddenSpeak(String content, long nowTime) {
		boolean forbidden = false;
		UserInfo userInfo = player.getUserInfo();
		if (userInfo.getForbiddenSpeakEndTime() > nowTime) {//被禁言
			forbidden = true;
		}
		//敏感字
		if (ForbiddenWordMgr.isForbidden(content)) {
			forbidden = true;
		}
		return forbidden;
	}

	public List<WorldMessageProto.WorldMessageTempMsg.Builder> getCrossMarriageGroupForbiddenMsg(){
		return new ArrayList<>(crossMarriageGroupForbiddenMessageMsgList);
	}

	public int canWorldChat(String content, long chatTime){
		if(player.getUserInfo().getVipExp() > GameConfig.CHAT_LIMIT_EXCEPTION_VIP
				|| player.getTitleId() > GameConfig.CHAT_LIMIT_EXCEPTION_TITLE){
			return 0;
		}
		if(WhiteWordMgr.isWhiteWord(content)){
			return 0;
		}
		if(isInForbiddenTime()){
			return GameErrorCode.E_WORLD_CHAT_FORBIDDEN;
		}
		if(WorldMessageMgr.isContentForbidden(content, chatTime)){//发了屏蔽词了，关小黑屋
			addForbiddenTime(GameConfig.CHAT_LIMIT_FORBIDDEN_TIME * 1000);
			return GameErrorCode.E_CHAT_FORBIDDEN;
		}
		return 0;
	}

	public boolean isInForbiddenTime(){
		long forbiddenEndTime = 0;
		if (null != userChat) {
			forbiddenEndTime = userChat.getWorldForbiddenEndTime();
		}
		return forbiddenEndTime > System.currentTimeMillis();
	}

	public void addForbiddenTime(long time){
		if (null == userChat) {
			UserChat temp = new UserChat();
			temp.setUserId(player.getUserId());
			temp.setWorldForbiddenEndTime(System.currentTimeMillis());
			temp.setInsertOption();
			userChat = temp;
		}
		long forbiddenEndTime = System.currentTimeMillis() + time;
		userChat.setWorldForbiddenEndTime(forbiddenEndTime);
	}

	public void syncChatControlData() {
		WorldMessageProto.ChatControlUserDataListSyncMsg.Builder syncMsg = WorldMessageProto.ChatControlUserDataListSyncMsg.newBuilder();
		for (BanChatUserData banChatUserData : ChatControlMgr.getBanChatUserList()) {
			syncMsg.addUserInfo(WorldMessagePb.parseChatControlUserMsg(banChatUserData));
		}
		player.sendPacket(ClientProtocol.U_CHAT_CONTROL_DATA_SYNC, syncMsg);
	}
}
